class Promise {
  /**
   * 手写 promise class 版本
   * @param executor (resolve, reject) => {}
   */
  constructor(executor) {
    const _this = this

    // 表示 promise 的状态
    this.PromiseState = 'pending'
    // 表示promise 的结果
    this.PromiseResult = null
    // 保存异步回调
    this.callback = {
      resolvedFn: [], rejectedFn: []
    }

    /**
     * 1、修改对象的状态 PromiseState
     * 2、设置对象结果值 PromiseResult
     * 3、执行器为异步任务时，调用成功的回调函数，回调函数异步执行
     * @param data
     */
    function resolve(data) {
      // 状态只能修改一次
      if (_this.PromiseState === 'pending') {
        // 1、修改对象的状态 PromiseState
        _this.PromiseState = 'fulfilled'
        // 2、设置对象结果值 PromiseResult
        _this.PromiseResult = data
        // 3、执行器为异步任务时，调用成功的回调函数，回调函数异步执行
        setTimeout(() => {
          _this.callback.resolvedFn.forEach(item => {
            item(data)
          })
        })
      }
    }

    /**
     * 1、修改对象的状态 PromiseState
     * 2、设置对象结果值 PromiseResult
     * 3、执行器为异步任务时，调用失败的回调函数，回调函数异步执行
     * @param data
     */
    function reject(data) {
      // 状态只能修改一次
      if (_this.PromiseState === 'pending') {
        // 1、修改对象的状态 PromiseState
        _this.PromiseState = 'rejected'
        // 2、设置对象结果值 PromiseResult
        _this.PromiseResult = data
        // 3、执行器为异步任务时，调用失败的回调函数，回调函数异步执行
        setTimeout(() => {
          _this.callback.rejectedFn.forEach(item => {
            item(data)
          })
        })
      }
    }

    // 处理抛出异常改变状态的情况
    try {
      // 执行器同步调用
      executor(resolve, reject)
    } catch (e) {
      // 修改promise状态
      reject(e)
    }
  }

  /**
   * promise then方法：返回一个promise
   * 1、处理执行器为同步任务时的回调
   * 2、处理执行器为异步任务时的回调
   *
   * 3、处理同一种状态指定多个回调的情况
   *
   * 4、处理执行器为同步任务时，then方法的返回结果
   * 5、处理执行器为异步任务时，then方法的返回结果
   *
   * 6、异常穿透，值传递
   * 7、回调函数异步执行
   * @param onResolved
   * @param onRejected
   * @returns {Promise}
   */
  then(onResolved, onRejected) {
    // 处理then方法第二个参数不传的情况（异常穿透）
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }

    // 处理then方法第一个不传的情况（值传递）
    if (typeof onResolved !== 'function') {
      onResolved = value => {
        return value
      }
    }

    // 处理then方法的返回结果
    return new Promise((resolve, reject) => {
      const _this = this

      // 处理回调
      function handleCallback(type) {
        try {
          // 获取回调函数的执行结果
          const res = type(_this.PromiseResult)
          if (res instanceof Promise) {
            // 如果回调函数返回的是Promise对象
            res.then(v => {
              resolve(v)
            }, r => {
              reject(r)
            })
          } else {
            // 如果回调函数返回的是结果为成功状态的一般对象
            resolve(res)
          }
        } catch (e) {
          reject(e)
        }
      }

      // 执行器为同步任务时
      // promise的状态为成功
      if (this.PromiseState === 'fulfilled') {
        // 回调函数异步执行
        setTimeout(() => {
          handleCallback(onResolved)
        })
      }

      // 执行器为同步任务时
      // promise的状态为失败
      if (this.PromiseState === 'rejected') {
        // 回调函数异步执行
        setTimeout(() => {
          handleCallback(onRejected)
        })
      }

      // 执行器为异步任务时
      if (this.PromiseState === 'pending') {
        // 保存回调函数
        // 处理同一种状态指定多个回调的情况，用数组收集

        // 收集成功的回调
        this.callback.resolvedFn.push(function () {
          handleCallback(onResolved)
        })

        // 收集失败的回调
        this.callback.rejectedFn.push(function () {
          handleCallback(onRejected)
        })
      }

    })
  }

  /**
   * then()的语法糖, 相当于: then(undefined, onRejected)
   * @param onRejected
   */
  catch(onRejected) {
    this.then(undefined, onRejected)
  }

  /**
   * 返回一个成功/失败的promise
   * @param value
   * @returns {Promise}
   */
  static resolve(value) {
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        resolve(value)
      }
    })
  }

  /**
   * 返回一个失败的promise
   * @param reason
   * @returns {Promise}
   */
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  /**
   * 返回一个新的 promise,
   * 只有所有的 promise 都成功才成功, 成果的结果为所有promise的结果；
   * 只要有一个失败了就直接失败，失败的结果为失败的那个promise返回的结果
   * @param promiseArr
   * @returns {Promise}
   */
  static all(promiseArr) {
    return new Promise((resolve, reject) => {
      // 记录成功的promise的个数
      let successCount = 0
      // 存储成功的promise的结果
      let result = []

      for (let i = 0; i < promiseArr.length; i++) {
        promiseArr[i].then(v => {
          // promise执行成功，计数+1
          successCount++
          result[i] = v
          // 所有的promise都成功，才执行resolve
          if (successCount === promiseArr.length) {
            resolve(result)
          }
        }, r => {
          // 有一个promise失败，直接执行reject
          reject(r)
        })
      }
    })
  }

  /**
   * 返回一个新的 promise,
   * 第一个完成的 promise 的状态和结果就是最终的状态和结果
   * @param promiseArr
   * @returns {Promise}
   */
  static race(promiseArr) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promiseArr.length; i++) {
        // 多个promise之间赛跑，谁快就返回谁
        promiseArr[i].then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      }
    })
  }
}